package hub

import (
	"log"
	"sync"

	"laravel-vue-admin/socket/client"
	"laravel-vue-admin/socket/message"
)

// Hub 维护所有活跃的客户端连接
type Hub struct {
	// 注册的客户端连接
	clients map[int64]*client.Client

	// 用户ID到客户端连接的映射（一个用户可能有多个连接）
	userClients map[int64]map[*client.Client]bool

	// 广播消息通道
	broadcast chan *message.Message

	// 注册通道
	register chan *client.Client

	// 注销通道
	unregister chan *client.Client

	// 互斥锁
	mu sync.RWMutex
}

// NewHub 创建新的Hub
func NewHub() *Hub {
	return &Hub{
		clients:     make(map[int64]*client.Client),
		userClients: make(map[int64]map[*client.Client]bool),
		broadcast:   make(chan *message.Message, 256),
		register:    make(chan *client.Client),
		unregister:  make(chan *client.Client),
	}
}

// Run 运行Hub
func (h *Hub) Run() {
	for {
		select {
		case client := <-h.register:
			h.registerClient(client)

		case client := <-h.unregister:
			h.unregisterClient(client)

		case msg := <-h.broadcast:
			h.broadcastMessage(msg)
		}
	}
}

// registerClient 注册客户端
func (h *Hub) registerClient(c *client.Client) {
	h.mu.Lock()
	defer h.mu.Unlock()

	// 添加到客户端映射
	h.clients[c.ID] = c

	// 添加到用户客户端映射
	if h.userClients[c.UserID] == nil {
		h.userClients[c.UserID] = make(map[*client.Client]bool)
	}
	h.userClients[c.UserID][c] = true

	log.Printf("客户端注册: ID=%d, UserID=%d, 当前在线用户数=%d", c.ID, c.UserID, len(h.userClients))
}

// unregisterClient 注销客户端
func (h *Hub) unregisterClient(c *client.Client) {
	h.mu.Lock()
	defer h.mu.Unlock()

	// 从客户端映射中删除
	delete(h.clients, c.ID)

	// 从用户客户端映射中删除
	if userClients, ok := h.userClients[c.UserID]; ok {
		delete(userClients, c)
		if len(userClients) == 0 {
			delete(h.userClients, c.UserID)
		}
	}

	// 关闭客户端发送通道
	close(c.Send)

	log.Printf("客户端注销: ID=%d, UserID=%d, 当前在线用户数=%d", c.ID, c.UserID, len(h.userClients))
}

// broadcastMessage 广播消息
func (h *Hub) broadcastMessage(msg *message.Message) {
	h.mu.RLock()
	defer h.mu.RUnlock()

	switch msg.Type {
	case message.TypeBroadcast:
		// 广播给所有客户端
		for _, client := range h.clients {
			select {
			case client.Send <- msg:
			default:
				close(client.Send)
				delete(h.clients, client.ID)
			}
		}

	case message.TypeUser:
		// 发送给指定用户的所有连接
		if userClients, ok := h.userClients[msg.ToUserID]; ok {
			for client := range userClients {
				select {
				case client.Send <- msg:
				default:
					close(client.Send)
					delete(h.userClients[msg.ToUserID], client)
					delete(h.clients, client.ID)
				}
			}
		}

	case message.TypeRoom:
		// 发送给房间内的所有用户（需要实现房间功能）
		// TODO: 实现房间功能
		log.Printf("房间消息: RoomID=%s, 暂未实现", msg.RoomID)
	}
}

// SendToUser 发送消息给指定用户
func (h *Hub) SendToUser(userID int64, msg *message.Message) {
	msg.Type = message.TypeUser
	msg.ToUserID = userID
	h.broadcast <- msg
}

// SendToUsers 发送消息给多个用户
func (h *Hub) SendToUsers(userIDs []int64, msg *message.Message) {
	h.mu.RLock()
	defer h.mu.RUnlock()

	for _, userID := range userIDs {
		if userClients, ok := h.userClients[userID]; ok {
			for client := range userClients {
				select {
				case client.Send <- msg:
				default:
					close(client.Send)
					delete(h.userClients[userID], client)
					delete(h.clients, client.ID)
				}
			}
		}
	}
}

// Broadcast 广播消息给所有用户
func (h *Hub) Broadcast(msg *message.Message) {
	msg.Type = message.TypeBroadcast
	h.broadcast <- msg
}

// GetOnlineUsers 获取在线用户列表
func (h *Hub) GetOnlineUsers() []int64 {
	h.mu.RLock()
	defer h.mu.RUnlock()

	users := make([]int64, 0, len(h.userClients))
	for userID := range h.userClients {
		users = append(users, userID)
	}
	return users
}

// IsUserOnline 检查用户是否在线
func (h *Hub) IsUserOnline(userID int64) bool {
	h.mu.RLock()
	defer h.mu.RUnlock()

	userClients, ok := h.userClients[userID]
	return ok && len(userClients) > 0
}

// GetUserConnections 获取用户的连接数
func (h *Hub) GetUserConnections(userID int64) int {
	h.mu.RLock()
	defer h.mu.RUnlock()

	userClients, ok := h.userClients[userID]
	if !ok {
		return 0
	}
	return len(userClients)
}

// Register 注册客户端
func (h *Hub) Register(client *client.Client) {
	h.register <- client
}

// Unregister 注销客户端
func (h *Hub) Unregister(client *client.Client) {
	h.unregister <- client
}

